package com.chenyue.cm;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.chenyue.cm.bean.CodeMakerBean;
import com.chenyue.cm.common.constant.ConstantValues;
import com.chenyue.cm.common.utils.Freemarker;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.*;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.*;
import java.util.regex.Matcher;

/**
 * 自定义封装 mybatis 逆向工程
 * ***********************************************
 *
 * @author chenyue
 * @date 2019/3/21
 */
public class CmDomainGenerator {


    private static final String DRIVER_CLASS = "com.mysql.jdbc.Driver";
    private static final String CONNECTION_URL = "jdbc:mysql://119.45.133.245:3306/jiedengtiyu";
    private static final String USER_ID = "root";
    private static final String PASSWORD = "Sxlongcai123.";


    private static final String BASE_PATH_JAVA = "src/main/java/";
    private static final String BASE_PATH_RESOURCE = "src/main/resources/";
    //    业务
//    private static final String PROJECT_PATH_DOMAIN = "/Users/libingxing/Desktop/svn/jiedeng/jiedengtiyu-shopping/";
//    private static final String PROJECT_PATH_ADMIN = "/Users/libingxing/Desktop/svn/jiedeng/jiedengtiyu-jiedeng/";
//    实体类
    private static final String PROJECT_PATH_DOMAIN = "F:/newPackage/SuQinghan/SuQinghan/project04/jiedengtiyu/jiedengtiyu-shopping/";
    private static final String PROJECT_PATH_ADMIN = "F:/newPackage/SuQinghan/SuQinghan/project04/jiedengtiyu/jiedengtiyu-shopping/";
//    private static final String PROJECT_PATH_DOMAIN = "D:/outSourceWorkspace/jiedeng/jiedengtiyu-domain/";
//    private static final String PROJECT_PATH_ADMIN = "D:/outSourceWorkspace/jiedeng/jiedengtiyu-jiedeng/";

    private static final String TARGET_PACKAGE_STRING = "com.chenyue.cm";
    private static final String TARGET_PACKAGE_PATH = "com/chenyue/cm/";

//	private static final String  TargetPackagPath2 = "com/master/";//临时使用


    private static final String OUT_FILE_PATH_DOMAIN = PROJECT_PATH_DOMAIN + BASE_PATH_JAVA + TARGET_PACKAGE_PATH;
    private static final String OUT_FILE_PATH_MAPPER = PROJECT_PATH_DOMAIN + BASE_PATH_JAVA + TARGET_PACKAGE_PATH;

    private static final String CONTEXT_PATH = "F:/newPackage/SuQinghan/SuQinghan/project04/jiedengtiyu/jiedengtiyu-modules-codemaker/" + BASE_PATH_RESOURCE;
//    private static final String CONTEXT_PATH = "D:/outSourceWorkspace/jiedeng/jiedengtiyu-modules-codemaker/" + BASE_PATH_RESOURCE;

    /**
     * 代码生成执行方法
     */
    public static void main(String[] args) throws Exception {

        /* A. 系统模块-----system*/
        String[] sysTables = new String[]{
                "sys_log", "sys_menus", "sys_role_menus",
                "sys_roles", "sys_users", "sys_users_role"
        };
//        dddddo(sysTables, "system");


        //门户官网模块
        String[] busTables = new String[]{
//                用户
//                "jd_app_user",
//                "jd_app_user_num",
//                "jd_verify",
//                "jd_sms_record",
//                "jd_user_relation",
//                "jd_user_collection",
//                "jd_member",
//                "jd_user_invite",
//                "view_invite_user",

//                组队
//                "jd_group",
//                "jd_group_user",
//                "group_info",
//                "view_my_group",

//                标签
//                "jd_label",
//                "jd_label_send",

//                机构申请
//                "jd_product",
//                "jd_third_information",

//                场馆
//                "jd_station",
//                "jd_station_apply",

//                新闻
//                "jd_news",
//                "jd_news_comment",
//                "jd_news_view_record",

//                消息
//                "jd_msg",
//                "jd_msg_type",

//                订单
//                "jd_order",
//                "jd_product",
//                "jd_product_type",

//                账户
//                "jd_account",
//                "jd_account_record",
//                "jd_account_source",
//                "jd_withdraw_apply",
//                "jd_bank_card_user",
//                "jd_bank_recharge_apply"

//                直播
//                "jd_live",
//                "jd_live_agree",
//                "jd_live_apply",
//                "jd_live_record",
//                "jd_live_type",
//                "jd_live_view_record",
//                "jd_live_gold_award",

//                赛事
//                "jd_match",
//                "jd_match_format",
//                "jd_match_appointment",
//                "jd_match_group",
//                "jd_match_item",
//                "jd_match_group_user",
//                "jd_match_score_apply",
//                "jd_match_sign",
//                "jd_match_type",
//                "jd_match_white_apply",
//                "jd_match_format_member",
//                "jd_match_live_user",
//                "view_match_score_record"
//                "format_live_user",
//                "format_live_record",
//                "match_info",
//                "my_match",
//                "view_score_apply",
//                "format_live_record",

//                通用
//                "jd_about_us",
//                "jd_app_version",
//                "jd_banner",
//                "sys_error_record",
//                "jd_user_opinion",
//                "jd_constant_values",
//                "jd_common_cron",
//                "jd_gold_sign",

//                 商城
//                "jd_goods_spu",             //---商品表
//                "jd_goods_stock_log",       //---商品库存变动表
//                "jd_order_comment",         //---订单评论信息
//                "jd_order_info",            //---订单主表
//                "jd_order_item",            //---订单子表
//                "jd_order_log",             //---订单日志表
//                "jd_order_logistics",       //---订单-物流表
//                "jd_order_money_log",       //---资金明细表
//                "jd_order_refund_apply",    //---退货申请表
//                 "jd_goods_info"              //---商品分类信息表
//                 "jd_goods_sku"
//                "jd_member_collect"           //-----会员收藏表
//                "jd_member_info"                //-----会员信息表
//                "jd_member_address"             //-----会员收货地址
//                "jd_member_shopping_cart"       // ------ 购物车
//                "jd_freight_template"               // ------ 运费模板
//                "jd_integral_record",            //-----积分记录表
//                "jd_integral_source",            //------积分来源
//                "jd_member_coupons"                 //------用户优惠券
//                "jd_discount_coupon"               //-----优惠券
//                "jd_deliver_address"                //------商户发货地址表
//                "v_getgoodsinfo"                     //
//                "jd_attr_key"                         //销售属性键
//                "jd_attr_value"                         //销售属性值
//                "jd_spec_grp",
//                "jd_spec_key",
//                "jd_spec_value"
//                "jd_shopping_banner"
                "jd_logistics_company"   //快递公司

        };
        dddddo(busTables, "user");

    }

    /**
     * 代码生成主模块
     *
     * @param tables String[] 表名数组
     * @param module 模块名称
     * @throws Exception null
     */
    private static void dddddo(String[] tables, String module) throws Exception {

        /*mybatis生成*/
        doMyBatis(tables, module);
        doMyBatisPlus(tables, module);
        /*mybatisPlus生成*/

        //业务层生成
        doYeWuJava(tables, module);
        //页面生成
//        doYeWuPage(tables, module);
    }

    /**
     * 生成业务service controller
     *
     * @param tableString 表名
     * @param module      模块前缀
     * @throws Exception null
     */
    private static void doYeWuJava(String[] tableString, String module) throws Exception {
        //4freemarker 生成业务层文件
        for (String tableName : tableString) {
            Map<String, Object> paramMap = new HashMap<>(3);
            //所属父模块
            paramMap.put("moudule", module);
            //所属父模块  包名前缀
            paramMap.put("targetPackageString", TARGET_PACKAGE_STRING);
            //模块描述
            paramMap.put("describe", tableName);
            CodeMakerBean cmb = new CodeMakerBean(tableName, paramMap, new ArrayList<>());
            Map<String, Object> dataMap = new HashMap<>(1);
            dataMap.put("vo", cmb);
            String pathSrcString = PROJECT_PATH_ADMIN + BASE_PATH_JAVA + TARGET_PACKAGE_PATH + module;
            System.out.println(pathSrcString);
            Freemarker.printFile("controller.ftl", dataMap, pathSrcString + "/controller/" + underlineToCamel("_" + tableName.replace("crm_", "")) + "Controller.java", CONTEXT_PATH);
            Freemarker.printFile("service.ftl", dataMap, pathSrcString + "/service/" + underlineToCamel("_" + tableName.replace("crm_", "")) + "Service.java", CONTEXT_PATH);
            Freemarker.printFile("serviceImpl.ftl", dataMap, pathSrcString + "/service/" + "impl/" + underlineToCamel("_" + tableName.replace("crm_", "")) + "ServiceImpl.java", CONTEXT_PATH);
        }
    }

    /**
     * 生成vue页面
     *
     * @param tableString 表名
     * @param module      模块前缀
     * @throws Exception null
     */
    private static void doYeWuPage(String[] tableString, String module) throws Exception {
        //5 freemarker 生成视图层文件
        for (String tableName : tableString) {
            Map<String, Object> paramMap = new HashMap<>(3);
            //所属父模块
            paramMap.put("moudule", module);
            //所属父模块  包名前缀
            paramMap.put("targetPackageString", TARGET_PACKAGE_STRING);
            //模块描述
            paramMap.put("describe", tableName);
            CodeMakerBean cmb = new CodeMakerBean(tableName.replace("crm_", ""), paramMap, new ArrayList<Map<String, Object>>());
            Map<String, Object> dataMap = new HashMap<>(1);
            dataMap.put("vo", cmb);
            String pathHtmlString = PROJECT_PATH_ADMIN + BASE_PATH_RESOURCE + "/templates/" + module;
            System.out.println(pathHtmlString);
            Freemarker.printFile("list.ftl", dataMap, pathHtmlString + "/" + underlineToCamel(tableName.replace("crm_", "")).toLowerCase() + "/" + underlineToCamel(tableName.replace("crm_", "")) + "List.html", CONTEXT_PATH);
            Freemarker.printFile("form.ftl", dataMap, pathHtmlString + "/" + underlineToCamel(tableName.replace("crm_", "")).toLowerCase() + "/" + underlineToCamel(tableName.replace("crm_", "")) + "Form.html", CONTEXT_PATH);
        }
    }

    /**
     * 生成实体类+xml
     *
     * @param tableString 表名
     * @param module      模块前缀
     * @throws Exception null
     */
    private static void doMyBatisPlus(String[] tableString, String module) throws Exception {
        //1 删除原来的domain
        for (String s : tableString) {
            String filePath = OUT_FILE_PATH_DOMAIN + module + "/domain/" + underlineToCamel("_" + s) + ".java";
            System.out.println(filePath);
            new File(filePath).delete();
            System.out.println(s);
        }
        //2生成plus对应的domain
        doGenerator(PROJECT_PATH_DOMAIN + BASE_PATH_JAVA, tableString, TARGET_PACKAGE_STRING + "." + module);

        //3freemarker 生成mapper文件
        for (String tableName : tableString) {
            Map<String, Object> paramMap = new HashMap<>(3);
            //所属父模块
            paramMap.put("moudule", module);
            //模块描述
            paramMap.put("describe", "");
            CodeMakerBean cmb = new CodeMakerBean(tableName, paramMap, new ArrayList<>());
            System.err.println(JSON.toJSONString(cmb));
            Map<String, Object> dataMap = new HashMap<>(1);
            dataMap.put("vo", cmb);
            Freemarker.printFile("mapper.ftl", dataMap, OUT_FILE_PATH_MAPPER + module + "/dao/" + underlineToCamel("_" + tableName) + "Mapper.java", CONTEXT_PATH);
        }
    }

    private static void doGenerator(String outFilePath, String[] tableString, String packageString) {

        AutoGenerator mpg = new AutoGenerator();
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());

        // 全局配置
        GlobalConfig gc = new GlobalConfig()
                // 打开文件
                .setOpen(false)
                // 文件覆盖
                .setFileOverride(true)
                // 开启activeRecord模式
                .setActiveRecord(true)
                // XML ResultMap: mapper.xml生成查询映射结果
//                .setBaseResultMap(true)
                // XML ColumnList: mapper.xml生成查询结果列
//                .setBaseColumnList(false)
                // XML 二级缓存
                .setEnableCache(false)
                // 输出目录
                .setOutputDir(outFilePath)
                // 主键自增
                .setIdType(IdType.AUTO)
                // 时间类型
                .setDateType(DateType.ONLY_DATE)
                // 作者
                .setAuthor("Lbx")
                // 开启swagger
                .setSwagger2(true);

        mpg.setGlobalConfig(gc);

        // 数据源配置
        mpg.setDataSource(getDsc());

        // 策略配置
        StrategyConfig strategy = new StrategyConfig()
                // 表名生成策略：下划线连转驼峰
                .setNaming(NamingStrategy.underline_to_camel)
                // 表字段生成策略：下划线连转驼峰
                .setColumnNaming(NamingStrategy.underline_to_camel)
                // 需要生成的表
                .setInclude(tableString)
                // 生成controller
//                .setRestControllerStyle(true)
                // 去除表前缀
//                .setTablePrefix("jd", "sys")
                // controller映射地址：驼峰转连字符
                .setControllerMappingHyphenStyle(false)
                // 是否启用builder 模式
//                .setEntityBuilderModel(true)
                // 是否为lombok模型; 需要lombok依赖
                .setEntityLombokModel(true)
                // restController 风格
//                .setRestControllerStyle(true)
                // 生成实体类字段注解
//                .setEntityTableFieldAnnotationEnable(true)
                // 乐观锁、逻辑删除、表填充
//                .setVersionFieldName("version")
//                .setLogicDeleteFieldName("deleted")
                .setTableFillList(Arrays.asList(
                        new TableFill("et", FieldFill.UPDATE),
                        new TableFill("ct", FieldFill.INSERT)
                ))
                // 生成类的时候排除的字符串
                .setSuperEntityColumns(
                        ""
                );
        mpg.setStrategy(strategy);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent(packageString);
        pc.setEntity("domain");
        pc.setMapper("dao");
        pc.setController("controller");
        pc.setService("service");
        mpg.setPackageInfo(pc);

        // 关闭默认 xml 生成，调整生成 至 根目录
        TemplateConfig tc = new TemplateConfig();
        tc.setController(null);
        tc.setService(null);
        tc.setMapper(null);
        tc.setServiceImpl(null);
        tc.setXml(null);
        mpg.setTemplate(tc);

        // 执行生成
        mpg.execute();

    }


    /**
     * 下划线格式字符串转换为驼峰格式字符串
     *
     * @param param 转换前字符串 jd_match
     * @return jdMatch
     */
    public static String underlineToCamel(String param) {
        if (StringUtils.isEmpty(param)) {
//            if (param == null || "".equals(param.trim())) {
            return "";
        }
        StringBuilder sb = new StringBuilder(param);
        Matcher mc = ConstantValues.COMPILE_WITH_.matcher(param);
        int i = 0;
        while (mc.find()) {
            int position = mc.end() - (i++);
            sb.replace(position - 1, position + 1, sb.substring(position, position + 1).toUpperCase());
        }
        return sb.toString();
    }


    /**
     * 生成 mapper+XML
     *
     * @param tables 表名
     * @param module 模块前缀
     */
    private static void doMyBatis(String[] tables, String module) {
        try {
            /* 配置xml配置项 */
            List<String> warnings = new ArrayList<>();
            boolean overwrite = true;
            Configuration config = new Configuration();
            Context context = new Context(ModelType.CONDITIONAL);
            context.setTargetRuntime("MyBatis3");
            context.setId("defaultContext");
            // 自动识别数据库关键字，默认false，如果设置为true，
            // 根据SqlReservedWords中定义的关键字列表；一般保留默认值，遇到数据库关键字（Java关键字），
            // 使用columnOverride覆盖
            context.addProperty("autoDelimitKeywords", "true");
            // 生成的Java文件的编码
            context.addProperty("javaFileEncoding", "utf-8");
            context.addProperty("beginningDelimiter", "`");
            context.addProperty("endingDelimiter", "`");
            // 格式化java代码
            context.addProperty("javaFormatter", "org.mybatis.generator.api.dom.DefaultJavaFormatter");
            // 格式化xml代码
            context.addProperty("xmlFormatter", "org.mybatis.generator.api.dom.DefaultXmlFormatter");

            // 格式化信息
            PluginConfiguration pluginConfiguration = new PluginConfiguration();
            pluginConfiguration.setConfigurationType("org.mybatis.generator.plugins.SerializablePlugin");
            pluginConfiguration.setConfigurationType("org.mybatis.generator.plugins.ToStringPlugin");
            context.addPluginConfiguration(pluginConfiguration);

            // 设置是否生成注释
            CommentGeneratorConfiguration commentGeneratorConfiguration = new CommentGeneratorConfiguration();
            commentGeneratorConfiguration.addProperty("suppressAllComments", "true");
            commentGeneratorConfiguration.addProperty("suppressDate", "true");
            context.setCommentGeneratorConfiguration(commentGeneratorConfiguration);

            // 设置连接数据库
            JDBCConnectionConfiguration jdbcConnectionConfiguration = new JDBCConnectionConfiguration();
            jdbcConnectionConfiguration.setDriverClass(DRIVER_CLASS);
            jdbcConnectionConfiguration.setConnectionURL(CONNECTION_URL);
            jdbcConnectionConfiguration.setUserId(USER_ID);
            jdbcConnectionConfiguration.setPassword(PASSWORD);
            context.setJdbcConnectionConfiguration(jdbcConnectionConfiguration);

            JavaTypeResolverConfiguration javaTypeResolverConfiguration = new JavaTypeResolverConfiguration();
            // 是否使用bigDecimal， false可自动转化以下类型（Long, Integer, Short, etc.）
            javaTypeResolverConfiguration.addProperty("forceBigDecimals", "false");
            context.setJavaTypeResolverConfiguration(javaTypeResolverConfiguration);

            // 生成实体类的地址
            JavaModelGeneratorConfiguration javaModelGeneratorConfiguration = new JavaModelGeneratorConfiguration();
            javaModelGeneratorConfiguration.setTargetPackage(TARGET_PACKAGE_STRING + "." + module + ".domain");
            javaModelGeneratorConfiguration.setTargetProject(PROJECT_PATH_DOMAIN + BASE_PATH_JAVA);
            javaModelGeneratorConfiguration.addProperty("enableSubPackages", "false");
            javaModelGeneratorConfiguration.addProperty("trimStrings", "true");
            context.setJavaModelGeneratorConfiguration(javaModelGeneratorConfiguration);

            // 生成的xml的地址
            SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration = new SqlMapGeneratorConfiguration();
            sqlMapGeneratorConfiguration.setTargetProject(PROJECT_PATH_DOMAIN + BASE_PATH_RESOURCE);
            sqlMapGeneratorConfiguration.setTargetPackage("mybatis." + module);
            sqlMapGeneratorConfiguration.addProperty("enableSubPackages", "false");
            context.setSqlMapGeneratorConfiguration(sqlMapGeneratorConfiguration);

            // 生成mapXml对应client，也就是接口dao
            String targetPackageDao = TARGET_PACKAGE_STRING + "." + module + ".dao";
            JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = new JavaClientGeneratorConfiguration();
            javaClientGeneratorConfiguration.setTargetPackage(targetPackageDao);
            javaClientGeneratorConfiguration.setTargetProject(PROJECT_PATH_DOMAIN + BASE_PATH_JAVA);
            javaClientGeneratorConfiguration.setConfigurationType("XMLMAPPER");
            javaClientGeneratorConfiguration.addProperty("enableSubPackages", "false");
            context.setJavaClientGeneratorConfiguration(javaClientGeneratorConfiguration);

            //table 表 设置
            for (String tableString : tables) {
                TableConfiguration tableConfiguration = getTableConfiguration(context, tableString);
                context.addTableConfiguration(tableConfiguration);
            }

            config.addContext(context);

            DefaultShellCallback callback = new DefaultShellCallback(overwrite);
            MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
            try {
                myBatisGenerator.generate(null);
            } catch (SQLException | IOException | InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } catch (InvalidConfigurationException e) {
            e.printStackTrace();
        }

    }

    /**
     * 获取表名配置
     *
     * @param context 自定义配置
     * @param tbName  表名
     * @return TableConfiguration
     */
    private static TableConfiguration getTableConfiguration(Context context, String tbName) {
        //table  表 设置
        TableConfiguration tableConfiguration = new TableConfiguration(context);
        tableConfiguration.setTableName(tbName);
        //不生成insert sql
        tableConfiguration.setInsertStatementEnabled(false);
        tableConfiguration.setCountByExampleStatementEnabled(true);
        tableConfiguration.setUpdateByExampleStatementEnabled(true);
        tableConfiguration.setDeleteByExampleStatementEnabled(true);
        GeneratedKey generatedKey = new GeneratedKey("id", "MySql", true, null);
        tableConfiguration.setGeneratedKey(generatedKey);
        //context.addTableConfiguration(tableConfiguration);
        return tableConfiguration;
    }


    /**
     * 获取数据源信息
     *
     * @return DataSourceConfig
     */
    private static DataSourceConfig getDsc() {
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MYSQL);
        //设置类型转换，不好使了
        dsc.setTypeConvert(new MySqlTypeConvertCustom());
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUrl(CONNECTION_URL);
        dsc.setUsername(USER_ID);
        dsc.setPassword(PASSWORD);
        return dsc;
    }

    /**
     * 自定义类型转换
     */
    static class MySqlTypeConvertCustom extends MySqlTypeConvert implements ITypeConvert {
        @Override
        public IColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
            String t = fieldType.toLowerCase();
            if (t.contains("tinyint(1)")) {
                return DbColumnType.INTEGER;
            }
            if (t.contains("timestamp(0)")) {
                return DbColumnType.DATE;
            }
            return super.processTypeConvert(globalConfig, fieldType);
        }
    }

}
